//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package wu2020.top.compare.orm.demo.config;

import net.hasor.cobble.logging.Logger;
import net.hasor.cobble.logging.LoggerFactory;
import net.hasor.dbvisitor.dal.dynamic.rule.RuleRegistry;
import net.hasor.dbvisitor.dal.mapper.Mapper;
import net.hasor.dbvisitor.dal.repository.DalMapper;
import net.hasor.dbvisitor.dal.repository.DalRegistry;
import net.hasor.dbvisitor.dal.session.DalSession;
import net.hasor.dbvisitor.dialect.SqlDialectRegister;
import net.hasor.dbvisitor.lambda.LambdaTemplate;
import net.hasor.dbvisitor.mapping.resolve.MappingOptions;
import net.hasor.dbvisitor.spring.boot.DbVisitorProperties;
import net.hasor.dbvisitor.spring.mapper.MapperFileConfigurer;
import net.hasor.dbvisitor.spring.mapper.MapperScannerConfigurer;
import net.hasor.dbvisitor.types.TypeHandlerRegistry;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.util.List;

@Configuration
@ConditionalOnClass({DalSession.class, DalRegistry.class})
//@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({DbVisitorProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class})
public class DynamicDbVisitorAutoConfiguration implements BeanClassLoaderAware, ApplicationContextAware, InitializingBean {
    private static final Logger logger = LoggerFactory.getLogger(DynamicDbVisitorAutoConfiguration.class);
    private ApplicationContext applicationContext;
    private ClassLoader classLoader;
    private final DbVisitorProperties properties;

    public DynamicDbVisitorAutoConfiguration(DbVisitorProperties properties) {
        this.properties = properties;
    }

    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void afterPropertiesSet() {
    }

    @Bean
    @ConditionalOnMissingBean
    public DalRegistry dalRegistry(ObjectProvider<TypeHandlerRegistry> typeHandlersProvider, ObjectProvider<RuleRegistry> ruleRegistryProvider) {
        TypeHandlerRegistry typeHandlerRegistry = (TypeHandlerRegistry) typeHandlersProvider.getIfAvailable();
        RuleRegistry ruleRegistry = (RuleRegistry) ruleRegistryProvider.getIfAvailable();
        MappingOptions options = MappingOptions.buildNew();
        options.setAutoMapping(this.properties.getAutoMapping());
        options.setMapUnderscoreToCamelCase(this.properties.getCamelCase());
        options.setCaseInsensitive(this.properties.getCaseInsensitive());
        options.setUseDelimited(this.properties.getUseDelimited());
        if (StringUtils.hasText(this.properties.getDialect())) {
            options.setDefaultDialect(SqlDialectRegister.findOrCreate(this.properties.getDialect(), this.classLoader));
        }

        return new DalRegistry(this.classLoader, typeHandlerRegistry, ruleRegistry, options);
    }

    @Bean
    @ConditionalOnMissingBean
    public DalSession dalSession(DataSource dataSource, DalRegistry dalRegistry) throws Exception {
        String refSessionBean = this.properties.getRefSessionBean();
        return StringUtils.hasText(refSessionBean) ? (DalSession) this.applicationContext.getBean(refSessionBean) : new DalSession(dataSource, dalRegistry);
    }

    @Bean
    @ConditionalOnMissingBean
    public LambdaTemplate lambdaTemplate(DataSource dataSource, ObjectProvider<TypeHandlerRegistry> typeHandlersProvider) {
        TypeHandlerRegistry typeHandlerRegistry = (TypeHandlerRegistry) typeHandlersProvider.getIfAvailable();
        return typeHandlerRegistry == null ? new LambdaTemplate(dataSource) : new LambdaTemplate(dataSource, typeHandlerRegistry);
    }

    public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar {
        private BeanFactory beanFactory;

        public AutoConfiguredMapperScannerRegistrar() {
        }

        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            this.beanFactory = beanFactory;
        }

        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            if (!AutoConfigurationPackages.has(this.beanFactory)) {
                DynamicDbVisitorAutoConfiguration.logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
            } else {
                DynamicDbVisitorAutoConfiguration.logger.debug("Searching for mappers annotated with @DalMapper");
                List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
                if (DynamicDbVisitorAutoConfiguration.logger.isDebugEnabled()) {
                    packages.forEach((pkg) -> {
                        DynamicDbVisitorAutoConfiguration.logger.debug("Using auto-configuration base package '" + pkg + "'");
                    });
                }

                String fileBeanName = MapperFileConfigurer.class.getName();
                BeanDefinitionBuilder fileBuilder = BeanDefinitionBuilder.genericBeanDefinition(MapperFileConfigurer.class);
                fileBuilder.addPropertyValue("processPropertyPlaceHolders", true);
                fileBuilder.addPropertyValue("mapperLocations", "${dbvisitor.mapper-locations:classpath*:/dbvisitor/mapper/**/*.xml}");
                fileBuilder.addPropertyValue("dalSessionRef", "${dbvisitor.ref-session-bean:}");
                registry.registerBeanDefinition(fileBeanName, fileBuilder.getBeanDefinition());
                String mapperBeanName = MapperScannerConfigurer.class.getName();
                BeanDefinitionBuilder mapperBuilder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
                mapperBuilder.addPropertyValue("mapperDisabled", "${dbvisitor.mapper-disabled:false}");
                mapperBuilder.addPropertyValue("processPropertyPlaceHolders", true);
                mapperBuilder.addPropertyValue("basePackage", "${dbvisitor.mapper-packages:" + StringUtils.collectionToCommaDelimitedString(packages) + "}");
                mapperBuilder.addPropertyValue("mapperFactoryBeanClassName", "${dbvisitor.mapper-factory-bean:}");
                mapperBuilder.addPropertyValue("defaultScope", "${dbvisitor.mapper-scope:}");
                mapperBuilder.addPropertyValue("lazyInitialization", "${dbvisitor.mapper-lazy-initialization:false}");
                mapperBuilder.addPropertyValue("nameGeneratorName", "${dbvisitor.mapper-name-generator:}");
                mapperBuilder.addPropertyValue("annotationClassName", "${dbvisitor.marker-annotation:" + DalMapper.class.getName() + "}");
                mapperBuilder.addPropertyValue("markerInterfaceName", "${dbvisitor.marker-interface:" + Mapper.class.getName() + "}");
                mapperBuilder.addPropertyValue("dalSessionRef", "${dbvisitor.ref-session-bean:}");
                mapperBuilder.addPropertyValue("dependsOn", fileBeanName);
                registry.registerBeanDefinition(mapperBeanName, mapperBuilder.getBeanDefinition());
            }
        }
    }

    @Configuration
    @Import({AutoConfiguredMapperScannerRegistrar.class})
    @ConditionalOnMissingBean({DalSession.class, MapperScannerConfigurer.class})
    public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
        public MapperScannerRegistrarNotFoundConfiguration() {
        }

        public void afterPropertiesSet() {
            DynamicDbVisitorAutoConfiguration.logger.debug("Not found configuration for registering mapper bean using @MapperScan, DalSessionBean and MapperScannerConfigurer.");
        }
    }

}
